package com.bootadmin.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bootadmin.controller.dto.FileVO;
import com.bootadmin.core.utils.SnowFlakeUtils;
import com.bootadmin.core.utils.StringUtils;
import com.bootadmin.core.web.FileResponse;
import com.bootadmin.core.web.ResultJson;
import com.bootadmin.entity.BaseFiles;
import com.bootadmin.service.BaseFilesService;
import com.bootadmin.service.QiniuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * @author kongzm
 * @description: 公共方法
 * @date 2022/7/8 14:04
 */
@RestController
@Tag(name = "公共方法")
@RequestMapping("/api/bootadmin/common")
public class PublicController {
    private final Logger logger = LoggerFactory.getLogger(PublicController.class);

    private final BaseFilesService baseFilesService;
    private final QiniuService qiniuService;

    private static final List<String> IMAGE_TYPE = Arrays.asList("jpg", "png", "svg", "jpeg", "jpeg2000", "bmg", "gif");
    private static final List<String> FILE_TYPE = Arrays.asList("docx", "doc", "xls", "xlsx", "pdf", "zip", "rar", "7z");
    private static final Long MAX_IMAGE_SIZE = 1024000L * 5L; // 10M
    private static final Long MAX_FILE_SIZE = 1024000L * 200L; // 200M

    public PublicController(BaseFilesService baseFilesService, QiniuService qiniuService) {
        this.baseFilesService = baseFilesService;
        this.qiniuService = qiniuService;
    }

    @PostMapping("/upload")
    @Operation(summary = "上传")
    public ResultJson upload(HttpServletRequest request) {
        FileVO fileVO = new FileVO();
        try {
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
            if (multipartResolver.isMultipart(request)) {
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                Iterator<String> iterator = multiRequest.getFileNames();
                if (iterator.hasNext()) {
                    MultipartFile file = multiRequest.getFile(iterator.next());
                    if (file == null) {
                        return ResultJson.failure("文件不能为空");
                    }
                    String OriginalFilename = file.getOriginalFilename();//获取原文件名
                    if (OriginalFilename == null) {
                        return ResultJson.failure("源文件名不能为空");
                    }

                    String suffixName = OriginalFilename.substring(OriginalFilename.lastIndexOf("."));
                    String extName = suffixName.replace(".", "");
                    if (StringUtils.isTrimEmpty(extName) || (!IMAGE_TYPE.contains(extName.trim().toLowerCase()) && !FILE_TYPE.contains(extName.trim().toLowerCase()))) {
                        return ResultJson.failure("文件格式错误");
                    }
                    if (FILE_TYPE.contains(extName.trim().toLowerCase()) && file.getSize() > MAX_FILE_SIZE) {
                        return ResultJson.failure("上传文件大小不能超过" + MAX_FILE_SIZE);
                    }

                    String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
                    if (StringUtils.isEmpty(md5)) {
                        return ResultJson.failure("上传文件异常。");
                    }

                    // 如果已经存在就直接返回
                    QueryWrapper<BaseFiles> query = new QueryWrapper<>();
                    query.eq("md5", md5);
                    BaseFiles baseFiles = baseFilesService.getOne(query);
                    if (baseFiles != null) {
                        fileVO.setFileId(baseFiles.getId());
                        fileVO.setFileUrl(baseFiles.getFileUrl());
                        return ResultJson.success(fileVO);
                    }

                    long fileKey = SnowFlakeUtils.nextId();
                    String rootPath = request.getSession().getServletContext().getRealPath("/");
                    String fileName = fileKey + suffixName;
                    String path = rootPath + "/" + fileName;

                    FileResponse fileResponse;
                    // 压缩
                    if (IMAGE_TYPE.contains(extName.trim().toLowerCase()) && file.getSize() > MAX_IMAGE_SIZE) {
                        logger.debug("********************图片压缩开始******************");
                        logger.debug(path);
                        logger.debug("大小：" + (file.getSize() / 1024) + "KB");
                        File beforeFile = new File(path);
                        // 生成本地图片
                        Thumbnails.of(file.getInputStream()).scale(1f).toFile(beforeFile);
                        // 压缩
                        commpressPicCycle(path, MAX_IMAGE_SIZE, 0.8);
                        File afterFile = new File(path);
                        logger.debug("压缩后大小：" + afterFile.length() / 1024 + "kb");
                        logger.debug("********************图片压缩结束******************");
                        InputStream inputStream = new FileInputStream(afterFile);
                        fileResponse = qiniuService.upload("bootadmin", fileName, inputStream);
                    } else {
                        fileResponse = qiniuService.upload("bootadmin", fileName, file.getInputStream());
                    }

                    if (fileResponse != null && fileResponse.getSuccess()) {
                        BaseFiles baseFiles1 = new BaseFiles();
                        baseFiles1.setFileKey(fileKey);
                        baseFiles1.setFileUrl(fileResponse.getFileUrl());
                        baseFiles1.setMd5(md5);
                        baseFilesService.save(baseFiles1);

                        fileVO.setFileUrl(baseFiles1.getFileUrl());
                        fileVO.setFileId(baseFiles1.getId());
                        return ResultJson.success(fileVO);
                    } else {
                        logger.error("七牛上传失败" + (fileResponse == null ? "null" : fileResponse.getMsg()));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultJson.failure("上传异常");
        }

        return ResultJson.failure("上传失败");
    }

    // // 获取文件md5
    // private String fileMd5(InputStream inputStream) {
    //     try {
    //         MessageDigest md = MessageDigest.getInstance("MD5");
    //         byte[] buffer = new byte[1024];
    //         int length;
    //         while ((length = inputStream.read(buffer, 0, 1024)) != -1) {
    //             md.update(buffer, 0, length);
    //         }
    //         inputStream.close();
    //         //转换并返回包含16个元素字节数组,返回数值范围为-128到127
    //         byte[] md5Bytes = md.digest();
    //         BigInteger bigInt = new BigInteger(1, md5Bytes);
    //         return bigInt.toString(16);
    //     } catch (NoSuchAlgorithmException | IOException e) {
    //         e.printStackTrace();
    //     }
    //
    //     return "";
    // }

    // 压缩
    private void commpressPicCycle(String desPath, long maxFileSize, double accuracy) throws IOException {
        File srcFileJPG = new File(desPath);
        //如果小于指定大小不压缩；如果大于等于指定大小压缩
        if (srcFileJPG.length() <= maxFileSize) {
            return;
        }
        // 计算宽高
        BufferedImage bim = ImageIO.read(srcFileJPG);
        int desWidth = new BigDecimal(bim.getWidth()).multiply(new BigDecimal(accuracy)).intValue();
        int desHeight = new BigDecimal(bim.getHeight()).multiply(new BigDecimal(accuracy)).intValue();
        Thumbnails.of(desPath).size(desWidth, desHeight).outputQuality(accuracy).toFile(desPath);
        commpressPicCycle(desPath, maxFileSize, accuracy);
    }
}
